package org.oschina.api.blog.blog.service;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.oschina.Config;
import org.oschina.Constants;
import org.oschina.Message;
import org.oschina.Module;
import org.oschina.ResultUtil;
import org.oschina.api.BaseService;
import org.oschina.api.blog.blog.BlogType;
import org.oschina.api.blog.blog.dao.BlogDAO;
import org.oschina.api.blog.blog.model.Blog;
import org.oschina.api.blog.blog.vo.BlogAccessVo;
import org.oschina.api.blog.blog.vo.BlogVo;
import org.oschina.api.blog.catalog.service.BlogCatalogService;
import org.oschina.api.blog.catalog.vo.BlogCatalogVo;
import org.oschina.api.blog.order.service.BlogOrderService;
import org.oschina.api.blog.order.vo.BlogOrderVo;
import org.oschina.api.comment.CommentCatalog;
import org.oschina.api.comment.service.CommentService;
import org.oschina.api.favorite.favorite.service.FavoriteService;
import org.oschina.api.favorite.type.FavoriteType;
import org.oschina.api.index.service.IndexService;
import org.oschina.api.manage.config.service.ConfigService;
import org.oschina.api.manage.module.ModuleType;
import org.oschina.api.manage.module.vo.ModuleVo;
import org.oschina.api.user.active.UserActiveType;
import org.oschina.api.user.active.service.UserActiveService;
import org.oschina.api.user.role.service.UserRoleService;
import org.oschina.api.user.user.model.User;
import org.oschina.api.user.user.service.UserService;
import org.oschina.bean.Pager;
import org.oschina.bean.Result;
import org.oschina.helper.index.IndexResultBean;
import org.oschina.security.AuthenticationException;
import org.oschina.security.ISecurity;
import org.oschina.security.annotation.Require;
import org.oschina.util.DateUtil;
import org.oschina.util.ListUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BlogService extends BaseService {

	@Autowired
	private BlogDAO blogDAO;
	@Autowired
	private IndexService indexServaice;
	@Autowired
	private CommentService commentService;
	@Autowired
	private ConfigService configService;
	@Autowired
	private UserService userService;
	@Autowired
	private BlogOrderService orderService;
	@Autowired
	private BlogCatalogService catalogService;
	@Autowired
	private UserRoleService roleService;
	@Autowired
	private ISecurity security;
	@Autowired
	private UserActiveService userActiveService;
	@Autowired
	private FavoriteService favoriteService;
	
	/**
	 * 收藏
	 * @param id
	 * @return
	 */
	@Require
	public Result createFavorite(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		User user=userService.getAuthenticationInfo(getToken());
		Result result=favoriteService.create(user.getId(), blogVo.getTitle(), id, FavoriteType.BLOG);
		
		if(result.isSuccess())
			_updateFavoriteCount_plus(blogVo);
		
		return result;
	}
	
	/**
	 * 删除收藏
	 * @param id
	 * @return
	 */
	@Require
	public Result deleteFavorite(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		User user=userService.getAuthenticationInfo(getToken());
		Result result=favoriteService.delete(user.getId(), id, FavoriteType.BLOG);
		
		if(result.isSuccess())
			_updateFavoriteCount_minus(blogVo);
		
		return result;
	}
	
	/**
	 * 根据作者返回最新
	 * @param author
	 * @return
	 */
	public List<BlogVo> findNewByAuthor(int author)
	{
		return _findVoByTypeAndAuthor(BlogType.SIMPLE, author, 0, _getHomePageCount());
	}

	/**
	 * 根据作者和目录返回
	 * @param author
	 * @param catalog
	 * @param pn
	 * @return
	 */
	public Pager<BlogVo> findByAuthorAndCatalog(int author,int catalog,int pn)
	{
		BlogCatalogVo catalogVo=catalogService._findVoById(catalog);
		if(catalogVo==null || !catalogService._isAuthor(author, catalogVo))
			return null;
		
		Pager<BlogVo> pager=new Pager(pn,_getCountByTypeAndAuthorAndCatalog(BlogType.SIMPLE,catalog,author),_getPageCount(),null);
		if(pager.getPage_count()!=0)
			pager.setData(_findVoByTypeAndAuthorAndCatalog(BlogType.SIMPLE, author ,catalog,pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 根据作者返回
	 * @param author
	 * @param pn
	 * @return
	 */
	public Pager<BlogVo> findByAuthor(int author,int pn)
	{
		Pager<BlogVo> pager=new Pager(pn,_getCountByTypeAndAuthor(BlogType.SIMPLE,author),_getPageCount(),null);
		if(pager.getPage_count()!=0)
			pager.setData(_findVoByTypeAndAuthor(BlogType.SIMPLE, author ,pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 设置/取消推荐
	 * @param id
	 * @return
	 */
	@Require(authorization=Module.MODULE_40)
	public Result setRecommend(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		if(_isRecommend(blogVo))
			_updateRecommendtime(blogVo.getId(), 0);
		else
			_updateRecommendtime(blogVo.getId(), DateUtil.now());
			
		return ResultUtil.getSuccess(Message.UPDATE_SUCCESS_DELAY);
	}
	
	/**
	 * 删除
	 * @param id
	 * @return
	 */
	@Require
	public Result delete(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		_require(getToken(), blogVo, new String[]{Module.MODULE_43}, new String[]{Module.MODULE_44});
		
		_setDelete(blogVo);
		catalogService._updateCount_minus(blogVo.getCatalog());
		return ResultUtil.getSuccess(Message.DELETE_SUCCESS);
	}
	
	/**
	 * 编辑
	 * @param blog
	 * @return
	 */
	@Require
	public Result edit(Blog blog)
	{
		BlogVo blogVo=_findVoById(blog.getId());
		if(blogVo==null || !_isSimple(blogVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		_require(getToken(), blogVo, new String[]{Module.MODULE_41}, new String[]{Module.MODULE_42});
		
		if(!blogVo.getOrder().getId().equals(blog.getOrder()))
		{
			BlogOrderVo order=orderService._findVoById(blog.getOrder());
			if(order==null)
				return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		}
		
		if(!blogVo.getCatalog().getId().equals(blog.getCatalog()))
		{
			BlogCatalogVo catalog=catalogService._findVoById(blog.getCatalog());
			if(catalog==null || !catalogService._isAuthor(blogVo.getAuthor().getId(), catalog))
				return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
			
			catalogService._updateCount_plus(catalog);
			catalogService._updateCount_minus(blogVo.getCatalog());
		}
		
		_edit(blog);
		return ResultUtil.getSuccess(blog);
	}
	
	/**
	 * 查看博客入口
	 * @param id
	 * @return
	 */
	public BlogAccessVo findById(int id)
	{
		User user=userService.getAuthenticationInfo(getToken());
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return null;
		
		if(blogVo.getOneself())
		{
			if(!_isAuthor(user, blogVo))
				blogVo.setContent(null);
		}
		
		BlogAccessVo blogAccessVo=new BlogAccessVo();
		blogAccessVo.setBlog(blogVo);
		blogAccessVo.setRelated(_findByRelated(blogVo, 0, _getRelatePageCount()));
		
		if(user!=null)
		{
			blogAccessVo.setFavorite(favoriteService._isFavorite(user.getId(), id, FavoriteType.BLOG));
			List<ModuleVo> module=roleService._findVoByRoleAndType(user, ModuleType.MODULE_16);
			if(_isAuthor(user, blogVo))
			{
				module.addAll(roleService._findVoByRoleAndType(user, ModuleType.MODULE_15));
				module=ListUtil.removeRepeat(module);
			}
			blogAccessVo.setModule(module);
		}
		
		_updateViewsCount_plus(blogVo);
		
		return blogAccessVo;
	}
	private int _getRelatePageCount()
	{
		return (Integer) configService.getValueById(Config.CONFIG_33, Integer.class);
	}

	/**
	 * 发表评论
	 * @param id
	 * @param content
	 * @param quote
	 * @return
	 */
	@Require
	public Result createComment(int id,String content,int quote)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo) || !blogVo.getComment())
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		Result result=commentService._create(blogVo.getId(), blogVo.getComment_id(), content, quote,CommentCatalog.BLOG);
		
		if(result.isSuccess())
		{
			_updateCommentCount_plus(blogVo);
			userActiveService.create(id, blogVo.getTitle(), content, UserActiveType.BLOG_COMMENT);
		}
		
		return result;
	}
	
	/**
	 * 返回推荐
	 * @param pn
	 * @return
	 */
	public Pager<BlogVo> findVoByRecommend(int pn)
	{
		Pager<BlogVo> pager=new Pager(pn,_getCountByTypeAndRecommend(BlogType.SIMPLE),_getPageCount(),null);
		if(pager.getPage_count()!=0)
			pager.setData(_findVoByTypeAndRecommend(BlogType.SIMPLE, pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 发表博客
	 * @param blog
	 * @return
	 */
	@Require(authorization=Module.MODULE_37)
	public Result create(Blog blog)
	{
		User user=userService.getAuthenticationInfo(getToken());
		BlogOrderVo order=orderService._findVoById(blog.getOrder());
		if(order==null)
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		BlogCatalogVo catalog=catalogService._findVoById(blog.getCatalog());
		if(catalog==null || !catalogService._isAuthor(user.getId(), catalog))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		blog=_create(blog,user,order,catalog);
		
		catalogService._updateCount_plus(catalog);
		userActiveService.create(blog.getId(), blog.getTitle(), blog.getContent(), UserActiveType.BLOG);
		
		return ResultUtil.getSuccess(blog);
	}
	
	/**
	 * 根据搜索返回
	 * @param keywords
	 * @param first
	 * @param max
	 * @return
	 */
	public Pager<BlogVo> findVoBySearch(String keyword,int pn)
	{
		String keywords[]=StringUtils.split(keyword," ");
		Pager pager=new Pager(pn,0,_getPageCount(),null);
		IndexResultBean indexResult=_searchVoByType(keywords,BlogType.SIMPLE, pager.getStart(), pager.getPage_count());
		pager.setData_sum(indexResult.getSum());
		pager.setData(indexResult.getResult());
		return pager;
	}
	
	/**
	 * 删除评论
	 * @param id
	 * @return
	 */
	public void _deleteComment(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return;
		
		_updateCommentCount_minus(blogVo);
	}
	
	/**
	 * 举报评论
	 * @param id
	 * @return
	 */
	public void _reportComment(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return;
		
		_updateCommentCount_minus(blogVo);
	}
	
	/**
	 * 恢复评论
	 * @param id
	 * @return
	 */
	public void _recoverComment(int id)
	{
		BlogVo blogVo=_findVoById(id);
		if(blogVo==null || !_isSimple(blogVo))
			return;
		
		_updateCommentCount_minus(blogVo);
	}
	
	/**
	 * 更新目录
	 * @param author
	 * @param type
	 * @param sourceCatalog
	 * @param targetCatalog
	 * @return
	 */
	public int _updateCatalogByAuthorAndType(int author,int type,int sourceCatalog,int targetCatalog)
	{
		return blogDAO.updateCatalogByAuthorAndType(author, type, sourceCatalog, targetCatalog);
	}
	
	/**
	 * 根据类型搜索
	 * @param keywords
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public IndexResultBean<BlogVo> _searchVoByType(String keywords[],int type,int first,int max)
	{
		return blogDAO.searchVoByType(keywords, type, first, max);
	}
	
	/**
	 * 根据类型和推荐返回
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	private List<BlogVo> _findVoByTypeAndRecommend(int type,int first,int max)
	{
		return blogDAO.findVoByTypeAndRecommend(type, first, max);
	}
	
	/**
	 * 返回推荐数量
	 * @param type
	 * @return
	 */
	private int _getCountByTypeAndRecommend(int type)
	{
		return blogDAO.getCountByTypeAndRecommend(type);
	}
	
	/**
	 * 根据类型和作者返回
	 * @param type
	 * @param author
	 * @param first
	 * @param max
	 * @return
	 */
	private List<BlogVo> _findVoByTypeAndAuthor(int type,int author,int first,int max)
	{
		return blogDAO.findVoByTypeAndAuthor(type,author,first,max);
	}
	
	/**
	 * 根据类型和作者返回数量
	 * @param type
	 * @return
	 */
	private int _getCountByTypeAndAuthor(int type,int author)
	{
		return blogDAO.getCountByTypeAndAuthor(type,author);
	}
	
	/**
	 * 根据类型和作者还有目录返回
	 * @param type
	 * @param author
	 * @param catalog
	 * @param first
	 * @param max
	 * @return
	 */
	private List<BlogVo> _findVoByTypeAndAuthorAndCatalog(int type,int author,int catalog,int first,int max)
	{
		return blogDAO.findVoByTypeAndAuthorAndCatalog(type, author, catalog, first, max);
	}
	
	/**
	 * 根据类型和作者返回数量
	 * @param type
	 * @param catalog
	 * @param author
	 * @return
	 */
	private int _getCountByTypeAndAuthorAndCatalog(int type,int catalog,int author)
	{
		return blogDAO.getCountByTypeAndAuthorAndCatalog(type, catalog, author);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public BlogVo _findVoById(int id)
	{
		return blogDAO.findVoById(id);
	}
	
	/**
	 * 返回相关博客
	 * @param blog
	 * @param first
	 * @param max
	 * @return
	 */
	private List<BlogVo> _findByRelated(BlogVo blog,int first,int max)
	{
		return blogDAO.findByRelated(blog, first, max);
	}
	
	/**
	 * 更新浏览数量
	 * @param id
	 * @param count
	 */
	private void _updateViewsCount_plus(BlogVo blogVo)
	{
		blogDAO.updateViewsCount(blogVo.getId(), 1);
	}
	
	/**
	 * 更新回复数量
	 * @param id
	 * @param count
	 */
	private void _updateCommentCount_plus(BlogVo blogVo)
	{
		blogDAO.updateCommentCount(blogVo.getId(), 1);
	}
	
	/**
	 * 更新浏览数量
	 * @param id
	 * @param count
	 */
	private void _updateViewsCount_minus(BlogVo blogVo)
	{
		blogDAO.updateViewsCount(blogVo.getId(), -1);
	}
	
	/**
	 * 更新回复数量
	 * @param id
	 * @param count
	 */
	private void _updateCommentCount_minus(BlogVo blogVo)
	{
		blogDAO.updateCommentCount(blogVo.getId(), -1);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	private void _updateFavoriteCount_plus(BlogVo blogVo)
	{
		blogDAO.updateFavoriteCount(blogVo.getId(), 1);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	private void _updateFavoriteCount_minus(BlogVo blogVo)
	{
		blogDAO.updateFavoriteCount(blogVo.getId(), -1);
	}
	
	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	private int _updateType(BlogVo blogVo,int type)
	{
		return blogDAO.updateType(blogVo.getId(),type);
	}
	
	/**
	 * 编辑
	 * @param blog
	 * @return
	 */
	private int _edit(Blog blog)
	{
		return blogDAO.edit(blog);
	}
	
	/**
	 * 更新推荐时间
	 * @param id
	 * @param time
	 * @return
	 */
	public int _updateRecommendtime(int id,long time)
	{
		return blogDAO.updateRecommendtime(id, time);
	}
	
	/**
	 * 创建
	 * @param blog
	 * @return
	 */
	private Blog _create(Blog blog,User user,BlogOrderVo order,BlogCatalogVo catalog)
	{
		blog.setId(_getIndex());
		blog.setAuthor(user.getId());
		blog.setOrder(order.getId());
		blog.setCatalog(catalog.getId());
		blog.setComment_id(_getCommentIndex());
		blog.setComment_count(0);
		blog.setViews_count(0);
		blog.setIp(user.getIp());
		blog.setFavorite_count(0);
		blog.setCreate_time(DateUtil.now());
		blog.setRecommend_time(0L);
		blog.setType(BlogType.SIMPLE);
		return blogDAO.create(blog);
	}
	
	private int _getIndex()
	{
		return indexServaice.getMajorById(Constants.INDEX_BLOG);
	}
	
	private int _getCommentIndex()
	{
		return commentService._getIndex();
	}
	
	private int _getPageCount()
	{
		return (Integer)configService.getValueById(Config.CONFIG_16, Integer.class);
	}
	
	private int _getHomePageCount()
	{
		return (Integer)configService.getValueById(Config.CONFIG_17, Integer.class);
	}
	
	private void _setSimple(BlogVo blogVo)
	{
		_updateType(blogVo,BlogType.SIMPLE);
	}
	
	private void _setCheck(BlogVo blogVo)
	{
		_updateType(blogVo,BlogType.CHECK);
	}
	
	private void _setDelete(BlogVo blogVo)
	{
		_updateType(blogVo,BlogType.DELETE);
	}
	
	public boolean _isSimple(BlogVo blogVo)
	{
		return blogVo.getType().equals(BlogType.SIMPLE);
	}
	
	private boolean _isCheck(BlogVo blogVo)
	{
		return blogVo.getType().equals(BlogType.CHECK);
	}
	
	private boolean _isDelete(BlogVo blogVo)
	{
		return blogVo.getType().equals(BlogType.DELETE);
	}
	
	/**
	 * 是否推荐
	 * @param blogVo
	 * @return
	 */
	public boolean _isRecommend(BlogVo blogVo)
	{
		return (blogVo.getRecommend_time()!=0);
	}
	
	/**
	 * 是否是作者
	 * @param user
	 * @param blogVo
	 * @return
	 */
	private boolean _isAuthor(User user,BlogVo blogVo)
	{
		if(user==null)
			return false;
		
		return (user.getId().equals(blogVo.getAuthor().getId()));
	}
	
	/**
	 * 验证
	 * @param blogVo 主题
	 * @param authority 主权限
	 * @param authorityOr
	 * @param authorAuthority 作者权限
	 * @param authorAuthorityOr
	 */
	public void _require(String token,BlogVo blogVo,String authority[],String authorAuthority[])
	{
		_require(token,blogVo,authority,false,authorAuthority,false);
	}
	public void _require(String token,BlogVo blogVo,String authority[],boolean authorityOr,String authorAuthority[],boolean authorAuthorityOr)
	{
		if(!security.require(authority, token, authorityOr))
		{
			User user=userService.getAuthenticationInfo(token);
			if(!_isAuthor(user,blogVo) || !security.require(authorAuthority, token, authorAuthorityOr))
				throw new AuthenticationException();
		}
	}
}